package com.nsn.vs.sdm.component.svn.event;

import org.apache.log4j.Logger;
import org.tmatesoft.svn.core.SVNCancelException;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNEvent;
import org.tmatesoft.svn.core.wc.SVNEventAction;
import org.tmatesoft.svn.core.wc.SVNStatusType;

import com.nsn.vs.sdm.component.svn.command.SvnCommand;

/**
 * The event handler for update client manager.
 * 
 * @author Jeccy.Zhao
 * 
 */
public class UpdateEventHandler implements ISVNEventHandler
{
	
	/**
	 * The LOGGER
	 */
	private static final Logger LOGGER = Logger.getLogger(UpdateEventHandler.class);
	
	/**
	 * The owner command for event handler
	 */
	private final SvnCommand command;
	
	public UpdateEventHandler (SvnCommand command)
	{
		this.command = command;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.tmatesoft.svn.core.ISVNCanceller#checkCancelled()
	 */
	@Override
	public void checkCancelled() throws SVNCancelException
	{
		
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.tmatesoft.svn.core.wc.ISVNEventHandler#handleEvent(org.tmatesoft.svn.core.wc.SVNEvent, double)
	 */
	@Override
	public void handleEvent(SVNEvent event, double progress)
			throws SVNException
	{
		/*
		 * Gets the current action. An action is represented by
		 * SVNEventAction. In case of an update an action can be determined
		 * via comparing SVNEvent.getAction() and
		 * SVNEventAction.UPDATE_-like constants.
		 */
		SVNEventAction action = event.getAction();
		String pathChangeType = " ";
		if (action == SVNEventAction.UPDATE_ADD)
		{
			/*
			 * the item was added
			 */
			pathChangeType = "A";
			
			LOGGER.info("A     " + event.getFile().getPath());
		} 
		else if (action == SVNEventAction.UPDATE_DELETE)
		{
			/*
			 * the item was deleted
			 */
			pathChangeType = "D";
			
			LOGGER.info("D     " + event.getFile().getPath());
		} 
		else if (action == SVNEventAction.UPDATE_UPDATE)
		{
			/*
			 * Find out in details what state the item is (after having been
			 * updated).
			 * 
			 * Gets the status of file/directory item contents. It is
			 * SVNStatusType who contains information on the state of an
			 * item.
			 */
			SVNStatusType contentsStatus = event.getContentsStatus();
			if (contentsStatus == SVNStatusType.CHANGED)
			{
				/*
				 * the item was modified in the repository (got the changes
				 * from the repository
				 */
				pathChangeType = "U";
				
				LOGGER.info("U     " + event.getFile().getPath());
			} 
			else if (contentsStatus == SVNStatusType.CONFLICTED)
			{
				/*
				 * The file item is in a state of Conflict. That is, changes
				 * received from the repository during an update, overlap
				 * with local changes the user has in his working copy.
				 */
				pathChangeType = "C";
				
				LOGGER.info("C     " + event.getFile().getPath());
			} 
			else if (contentsStatus == SVNStatusType.MERGED)
			{
				/*
				 * The file item was merGed (those changes that came from
				 * the repository did not overlap local changes and were
				 * merged into the file).
				 */
				pathChangeType = "G";
				
				LOGGER.info("G     " + event.getFile().getPath());
			}
			else if (contentsStatus == SVNStatusType.INAPPLICABLE)
			{
				/*
				 * the item was committed to repository
				 */
				pathChangeType = "A";
				
				LOGGER.info("A     " + event.getFile().getPath());
			}
		} 
		else if (action == SVNEventAction.UPDATE_EXTERNAL)
		{
			/* for externals definitions */
			LOGGER.info("Fetching external item into '"
					+ event.getFile().getAbsolutePath() + "'");
			LOGGER.info("External at revision "
					+ event.getRevision());
			return;
		} 
		else if (action == SVNEventAction.UPDATE_UPDATE)
		{
			this.command.getSvnClient().appendMessage("At revision " + event.getRevision());
			System.out.println("At revision " + event.getRevision());
			return;
		}
		else if (action == SVNEventAction.UPDATE_COMPLETED)
		{
			/*
			 * Working copy update is completed. Prints out the revision.
			 */
			this.command.getSvnClient().appendMessage("At revision " + event.getRevision());
			LOGGER.info("At revision " + event.getRevision());
			return;
		} 
		else if (action == SVNEventAction.COMMIT_COMPLETED)
		{
			/*
			 * Working copy update is completed. Prints out the revision.
			 */
			this.command.getSvnClient().appendMessage("At revision " + event.getRevision());
			LOGGER.info("At revision " + event.getRevision());
			return;
		} 
		else if (action == SVNEventAction.ADD)
		{
			LOGGER.info("A     " + event.getFile().getPath());
			return;
		} 
		else if (action == SVNEventAction.COMMIT_ADDED)
		{
			LOGGER.info("C     " + event.getFile().getPath());
			return;
		}
		else if (action == SVNEventAction.DELETE)
		{
			LOGGER.info("D     " + event.getFile().getPath());
			return;
		} 
		else if (action == SVNEventAction.LOCKED)
		{
			LOGGER.info("L     " + event.getFile().getPath());
			return;
		}
		else if (action == SVNEventAction.LOCK_FAILED)
		{
			LOGGER.info("failed to lock    " + event.getFile().getPath());
			return;
		}

		/*
		 * Status of properties of an item. SVNStatusType also contains
		 * information on the properties state.
		 */
		SVNStatusType propertiesStatus = event.getPropertiesStatus();
		String propertiesChangeType = " ";
		if (propertiesStatus == SVNStatusType.CHANGED)
		{
			/*
			 * Properties were updated.
			 */
			propertiesChangeType = "U";
		} 
		else if (propertiesStatus == SVNStatusType.CONFLICTED)
		{
			/*
			 * Properties are in conflict with the repository.
			 */
			propertiesChangeType = "C";
		} 
		else if (propertiesStatus == SVNStatusType.MERGED)
		{
			/*
			 * Properties that came from the repository were merged with the
			 * local ones.
			 */
			propertiesChangeType = "G";
		}
		else if (propertiesStatus == SVNStatusType.INAPPLICABLE)
		{
			/*
			 * Properties are committed
			 */
			propertiesChangeType = "A";
		}

		/*
		 * Gets the status of the lock.
		 */
		String lockLabel = " ";
		SVNStatusType lockType = event.getLockStatus();

		if (lockType == SVNStatusType.LOCK_UNLOCKED)
		{
			/*
			 * The lock is broken by someone.
			 */
			lockLabel = "B";
		}
		
		String message = pathChangeType + propertiesChangeType 
				+ lockLabel + "       " + event.getFile().getPath();
		
		if (this.command != null)
		{
			this.command.getSvnClient().appendMessage(message);
		}
		else
		{
			LOGGER.info(message);
		}
	}

	public SvnCommand getCommand()
	{
		return command;
	}

}
